package net.biz.dao.impl;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.collections.CollectionUtils;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import net.biz.Page;
import net.biz.Pageable;
import net.biz.dao.NativeBaseDao;
import net.biz.dto.DTOTransformer;


@Repository("nativeBaseDaoImpl")
public class NativeBaseDaoImpl implements NativeBaseDao {

	@PersistenceContext
	protected EntityManager entityManager;

	@Override
	public <T> Page<T> findPage(String sql, Map<String, Object> params,Pageable pageable, Class<T> clazz) {
		Query count = entityManager.createNativeQuery("SELECT COUNT(1) FROM ("+ sql + ") as total");
		Query query = entityManager.createNativeQuery(sql);
		if (params != null) {
			for (Entry<String, Object> e : params.entrySet()) {
				if(e.getValue() == null) {
					continue;
				}
				count.setParameter(e.getKey(), e.getValue());
				query.setParameter(e.getKey(), e.getValue());
			}
		}
		long total = 0;
		BigInteger totalTemp = new BigInteger("0");
		totalTemp =(BigInteger)count.getSingleResult();
		total=totalTemp.longValue();
		if (total == 0) {
			return new Page<T>(new ArrayList<T>(), 0, pageable);
		}
		if (pageable == null) {
			pageable = new Pageable();
		}
		int totalPages = (int) Math.ceil((double) total
				/ (double) pageable.getPageSize());
		if (totalPages < pageable.getPageNumber()) {
			pageable.setPageNumber(totalPages);
		}
		query.unwrap(SQLQuery.class).setResultTransformer(new DTOTransformer<T>(clazz));
		query.setMaxResults(pageable.getPageSize());
		query.setFirstResult((pageable.getPageNumber() - 1)* pageable.getPageSize());
		@SuppressWarnings("unchecked")
		List<T> result = ((List<T>) query.getResultList());
		return new Page<T>(result, total, pageable);
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public <T> List<T> findList(String sql, Map<String, Object> params,
			Class<T> clazz) {
		Query query = entityManager.createNativeQuery(sql);
		if (params != null) {
			for (Entry<String, Object> e : params.entrySet()) {
				query.setParameter(e.getKey(), e.getValue());
			}
		}
		query.unwrap(SQLQuery.class).setResultTransformer(
				new DTOTransformer<T>(clazz));
		return query.getResultList();
	}
	
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	@SuppressWarnings("unchecked")
	@Override
	public List<Map<String,Object>> excelExportList (String sql,Map<String,Object> params,@SuppressWarnings("rawtypes") Class<? extends HashMap> class1) {
		Query query = entityManager.createNativeQuery(sql);
		if (params != null) {
			for (Iterator<String> it = params.keySet().iterator();it.hasNext();) {
				String keyV = it.next();
				if(params.get(keyV) != null) {
					 query.setParameter(keyV, params.get(keyV));
				}
			}
		}
		return query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
	}

	@Override
	public <T> T findOne(String sql, Map<String, Object> params, Class<T> clazz) {
		List<T> result = findList(sql, params, clazz);
		if (result == null | result.size() == 0) {
			return null;
		}
		if (result.size() > 1) {
			// TODO:EXCEPTION-- More than one element found
		}
		return result.get(0);
	}
	
	public int count(String sql,Map<String,Object> params){
		Query query = entityManager.createNativeQuery(sql);
		if (params != null) {
			for (Entry<String, Object> e : params.entrySet()) {
				query.setParameter(e.getKey(), e.getValue());
			}
		}
		return ((Number) query.getSingleResult()).intValue();
	}

	/**
	 * 查询 参数和值要一一对应
	 * (non-Javadoc)
	 * @param sql
	 * @param clazz
	 * @param params
	 * @param values
	 * @return
	 * @throws RuntimeException
	 * @see com.eshop.dao.NativeBaseDao#findList(String, Class, String[], Object[])
	 */
	@Override
	public <T> List<T> findList(String sql, Class<T> clazz, String[] params,Object... values) throws RuntimeException{
		Map<String,Object> tempMap = new HashMap<String, Object>();
		if(params == null || (params != null && params.length == 0)) {
			return findList(sql, tempMap, clazz);
		}
		if(params.length != values.length ) {
			throw new RuntimeException("参数和值不匹配");
		}
		for(int i=0;i<params.length; i++) {
			tempMap.put(params[i], values[i]);
		}
		return findList(sql, tempMap, clazz);
	}

	@Override
	public <T> T findOne(String string, Class<T> class1, String[] strings,Object... values) throws RuntimeException {
		List<T> tempList = findList(string, class1, strings, values);
		if(CollectionUtils.isNotEmpty(tempList)) {
			return tempList.get(0);
		}
		return null;
	}
}
